﻿using System;
using System.Drawing;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.InteropServices;

namespace JN.Utility
{
    [Serializable, StructLayout(LayoutKind.Sequential), ComVisible(true)]
    public struct SizeD
    {
        public static readonly SizeD Empty;
        private double _width;
        private double _height;

        [Browsable(false)]
        public bool IsEmpty
        {
            get { return ((this._width == 0f) && (this._height == 0f)); }
        }

        public double Width
        {
            get { return this._width; }
            set { this._width = value; }
        }

        public double Height
        {
            get { return this._height; }
            set { this._height = value; }
        }

        public SizeD(SizeD size)
        {
            this._width = size._width;
            this._height = size._height;
        }

        public SizeD(PointD pt)
        {
            this._width = pt.X;
            this._height = pt.Y;
        }

        public SizeD(double width, double height)
        {
            this._width = width;
            this._height = height;
        }

        public void Rotation(double angle)
        {
            if (angle == 0.0)
            {
                return;
            }
            double distance = Math.Sqrt((_width * _width) + (_height * _height));
            double d = Math.Atan2(_height, _width) + angle;

            _width = (float)(distance * Math.Cos(d));
            _height = (float)(distance * Math.Sin(d));
        }

        public void Mirror(bool isMirrorX, bool isMirrorY)
        {
            _width = (isMirrorX ? -_width : _width);
            _height = (isMirrorY ? -_height : _height);
        }

        public void Scale(double xScale, double yScale)
        {
            _width = (float)(_width * xScale);
            _height = (float)(_height * yScale);
        }

        public static SizeD operator +(SizeD sz1, SizeD sz2)
        {
            return Add(sz1, sz2);
        }

        public static SizeD operator -(SizeD sz1, SizeD sz2)
        {
            return Subtract(sz1, sz2);
        }

        public static bool operator ==(SizeD sz1, SizeD sz2)
        {
            return ((sz1.Width == sz2.Width) && (sz1.Height == sz2.Height));
        }

        public static bool operator !=(SizeD sz1, SizeD sz2)
        {
            return !(sz1 == sz2);
        }

        public static explicit operator PointF(SizeD size)
        {
            return new PointF(Convert.ToSingle(size.Width), Convert.ToSingle(size.Height));
        }

        public static SizeD Add(SizeD sz1, SizeD sz2)
        {
            return new SizeD(sz1.Width + sz2.Width, sz1.Height + sz2.Height);
        }

        public static SizeD Subtract(SizeD sz1, SizeD sz2)
        {
            return new SizeD(sz1.Width - sz2.Width, sz1.Height - sz2.Height);
        }

        public override bool Equals(object obj)
        {
            if (!(obj is SizeD))
            {
                return false;
            }
            SizeD ef = (SizeD)obj;
            return (((ef.Width == this.Width) && (ef.Height == this.Height)) && ef.GetType().Equals(base.GetType()));
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override string ToString()
        {
            return ("{Width=" + this._width.ToString(CultureInfo.CurrentCulture) + ", Height=" + this._height.ToString(CultureInfo.CurrentCulture) + "}");
        }

        static SizeD()
        {
            Empty = new SizeD();
        }


        public static implicit operator Size(SizeD sz)
        {
            return new Size(Convert.ToInt32(sz.Width), Convert.ToInt32(sz.Height));
        }

        public static implicit operator SizeF(SizeD sz)
        {
            return new SizeF(Convert.ToSingle(sz.Width), Convert.ToSingle(sz.Height));
        }

        public static implicit operator SizeD(SizeF sz)
        {
            return new SizeD(sz.Width, sz.Height);
        }

        public static implicit operator SizeD(Size sz)
        {
            return new SizeD(sz.Width,sz.Height);
        }

    }
}
